import {
  BadRequestException,
  Body,
  Controller,
  DefaultValuePipe,
  Get,
  HttpStatus,
  Param,
  Post,
  Query,
  SerializeOptions,
  UnauthorizedException,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UserService } from './user.service';
import { RegisterDto } from './dtos/register.dto';
import { EmailService } from 'src/email/email.service';
import { RedisService } from 'src/redis/redis.service';
import { LoginDto } from './dtos/login.dto';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { RequireLogin, UserInfo } from 'src/decorators/custom-decorator';
import { UpdatePasswordDto } from './dtos/updatePassword.dto';
import { LoginReturn, UpdateUserDto } from './dtos/updateUser.dto';
import { generateParseIntPipe } from 'src/utils';
import {
  ApiBearerAuth,
  ApiBody,
  ApiParam,
  ApiQuery,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { LoginUserVo, UserInfoVo } from './vo/login-user.vo';
import { RefreshTokenVo } from './vo/refresh-token.vo';
import { FileInterceptor } from '@nestjs/platform-express';
import * as path from 'path';
import { storage } from 'src/my-file-storage';

@ApiTags('用户管理模块')
@Controller('user')
export class UserController {
  constructor(
    private userService: UserService,
    private emailService: EmailService,
    private redisService: RedisService,
    private jwtService: JwtService,
    private configService: ConfigService,
  ) {}
  @ApiBody({ type: RegisterDto })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    type: String,
    description: '验证码已失效/验证码不正确/用户已存在',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    type: String,
    description: '注册成功/失败',
  })
  @Post('register')
  async register(@Body() registerDto: RegisterDto) {
    return await this.userService.register(registerDto);
  }
  // 登录
  @ApiBody({ type: LoginDto })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '用户信息和token',
    type: LoginUserVo,
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '用户不存在/密码错误',
    type: String,
  })
  @SerializeOptions({ groups: ['login'] })
  @Post('login')
  async userLogin(@Body() loginDto: LoginDto) {
    const vo = await this.userService.login(loginDto, false);
    const user: LoginReturn = {
      userInfo: vo,
      accessToken: this.jwtService.sign(
        {
          userId: vo.id,
          username: vo.username,
          email: vo.email,
          roles: vo.roles,
          permissions: vo.permissions,
        },
        {
          expiresIn: this.configService.get('jwt.expiresIn') || '30m',
        },
      ),
      refreshToken: this.jwtService.sign(
        {
          userId: vo.id,
        },
        {
          expiresIn:
            this.configService.get('jwt.refreshTokenExpiresIn') || '7d',
        },
      ),
    };
    // vo.accessToken = this.jwtService.sign(
    //   {
    //     userId: vo.userInfo.id,
    //     username: vo.userInfo.username,
    //     roles: vo.userInfo.roles,
    //     permissions: vo.userInfo.permissions,
    //   },
    //   {
    //     expiresIn:
    //       this.configService.get('jwt_access_token_expries_time') || '30m',
    //   },
    // );
    // vo.refreshToken = this.jwtService.sign(
    //   {
    //     userId: vo.userInfo.id,
    //   },
    //   {
    //     expiresIn:
    //       this.configService.get('jwt_refresh_token_expries_time') || '7d',
    //   },
    // );
    return user;
  }
  // 后台管理员登录
  @ApiBody({ type: LoginDto })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '用户信息和token',
    type: LoginUserVo,
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '用户不存在/密码错误',
    type: String,
  })
  @Post('admin/login')
  async login(@Body() loginDto: LoginDto) {
    const vo = await this.userService.login(loginDto, true);
    const user: LoginReturn = {
      userInfo: vo,
      accessToken: this.jwtService.sign(
        {
          userId: vo.id,
          username: vo.username,
          email: vo.email,
          roles: vo.roles,
          permissions: vo.permissions,
        },
        {
          expiresIn: this.configService.get('jwt.expiresIn') || '30m',
        },
      ),
      refreshToken: this.jwtService.sign(
        {
          userId: vo.id,
        },
        {
          expiresIn:
            this.configService.get('jwt.refreshTokenExpiresIn') || '7d',
        },
      ),
    };

    return user;
  }
  // 用户端刷新token
  @ApiQuery({
    name: 'refreshToken',
    type: String,
    description: '刷新token',
    required: true,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: 'token已失效，请重新登录',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '刷新成功',
    type: RefreshTokenVo,
  })
  @Get('refresh')
  async refresh(@Query('refreshToken') refreshToken: string) {
    try {
      const data = await this.jwtService.verify(refreshToken);
      const user = await this.userService.findUserById(data.userId, false);
      const access_token = this.jwtService.sign(
        {
          userId: user.id,
          username: user.username,
          email: user.email,
          roles: user.roles,
          permissions: user.permissions,
        },
        {
          expiresIn: this.configService.get('jwt.expiresIn') || '30m',
        },
      );
      const refresh_token = this.jwtService.sign(
        {
          userId: user.id,
        },
        {
          expiresIn:
            this.configService.get('jwt.refreshTokenExpiresIn') || '7d',
        },
      );
      const vo = new RefreshTokenVo();
      vo.accessToken = access_token;
      vo.refreshToken = refresh_token;
      return vo;
    } catch (e) {
      throw new UnauthorizedException('token已失效，请重新登录');
    }
  }
  // 后台刷新token
  @ApiQuery({
    name: 'refreshToken',
    type: String,
    description: '刷新token',
    required: true,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: 'token已失效，请重新登录',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '刷新成功',
    type: RefreshTokenVo,
  })
  @Get('admin/refresh')
  async refreshAdmin(@Query('refreshToken') refreshToken: string) {
    try {
      const data = await this.jwtService.verify(refreshToken);
      const user = await this.userService.findUserById(data.userId, true);
      const access_token = this.jwtService.sign(
        {
          userId: user.id,
          username: user.username,
          email: user.email,
          roles: user.roles,
          permissions: user.permissions,
        },
        {
          expiresIn: this.configService.get('jwt.expiresIn') || '30m',
        },
      );
      const refresh_token = this.jwtService.sign(
        {
          userId: user.id,
        },
        {
          expiresIn:
            this.configService.get('jwt.refreshTokenExpiresIn') || '7d',
        },
      );
      return {
        accessToken: access_token,
        refreshToken: refresh_token,
      };
    } catch (e) {
      throw new UnauthorizedException('token已失效，请重新登录');
    }
  }

  @Get('initData')
  async initData() {
    await this.userService.initData();
    return 'done';
  }

  // 用户端获取用户信息
  @ApiBearerAuth()
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'success',
    type: UserInfoVo,
  })
  @Get('info')
  @RequireLogin()
  async info(@UserInfo('userId') userId: number) {
    const user = await this.userService.findUserById(userId, false);
    const vo = new UserInfoVo();
    vo.id = user.id;
    vo.username = user.username;
    vo.nickName = user.nickName;
    vo.email = user.email;
    vo.headPic = user.headPic;
    vo.phoneNumber = user.phoneNumber;
    vo.isFrozen = user.isFrozen;
    vo.isAdmin = user.isAdmin;
    vo.createTime = user.createTime;
    vo.roles = user.roles;
    vo.permissions = user.permissions;
    return vo;
  }
  // 管理端获取用户信息
  @ApiBearerAuth()
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'success',
    type: UserInfoVo,
  })
  @Get('admin/info')
  @RequireLogin()
  async adminInfo(@UserInfo('userId') userId: number) {
    console.log(userId);
    return await this.userService.findUserById(userId, true);
  }
  // 修改密码
  @ApiBody({
    type: UpdatePasswordDto,
  })
  @ApiResponse({
    type: String,
    description: '验证码已失效/不正确',
  })
  @Post(['update_password', 'admin/update_password'])
  async updatePassword(@Body() updatePasswordDto: UpdatePasswordDto) {
    return await this.userService.updatePassword(updatePasswordDto);
  }
  // 修改个人信息
  @ApiBearerAuth()
  @ApiBody({
    type: UpdatePasswordDto,
  })
  @ApiResponse({
    type: String,
    description: '验证码已失效/不正确',
  })
  @RequireLogin()
  @Post(['update', 'admin/update'])
  async updateUser(
    @UserInfo('userId') userId: number,
    @Body() updateUserDto: UpdateUserDto,
  ) {
    return await this.userService.updateUser(userId, updateUserDto);
  }
  // 发送验证码
  @ApiQuery({
    name: 'address',
    type: String,
    description: '邮箱地址',
    required: true,
    example: 'xxx@xx.com',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '发送成功',
    type: String,
  })
  @Get('register-captcha')
  async captcha(@Query('address') address: string) {
    const code = Math.random().toString().slice(2, 8);
    await this.redisService.set(`captcha_${address}`, code, 5 * 60);

    await this.emailService.sendMail({
      to: address,
      subject: '注册验证码',
      html: `<p>你的注册验证码是${code}</p>`,
    });
    return '发送成功';
  }
  // 修改密码发送验证码
  @ApiBearerAuth()
  @ApiQuery({
    name: 'address',
    description: '邮箱地址',
    type: String,
  })
  @ApiResponse({
    type: String,
    description: '发送成功',
  })
  @Get('updatePassword/captcha')
  async updateCaptcha(@Query('address') address: string) {
    const code = Math.random().toString().slice(2, 8);
    await this.redisService.set(`updatePassword_${address}`, code, 5 * 60);
    await this.emailService.sendMail({
      to: address,
      subject: '修改密码验证码',
      html: `<p>您的验证码是${code}</p>`,
    });
    return '发送成功';
  }
  // 修改密码发送验证码
  @ApiBearerAuth()
  // @ApiQuery({
  //   name: 'address',
  //   description: '邮箱地址',
  //   type: String,
  // })
  @ApiResponse({
    type: String,
    description: '发送成功',
  })
  @RequireLogin()
  @Get('updateUser/captcha')
  async updateUserCaptcha(@UserInfo('email') address: string) {
    console.log(address);
    const code = Math.random().toString().slice(2, 8);
    await this.redisService.set(`updateUser_${address}`, code, 5 * 60);
    await this.emailService.sendMail({
      to: address,
      subject: '修改用户信息验证码',
      html: `<p>您的验证码是${code}</p>`,
    });
    return '发送成功';
  }
  // 冻结用户
  @ApiBearerAuth()
  @ApiParam({
    name: 'id',
    description: 'userId',
    type: Number,
  })
  @ApiResponse({
    type: String,
    description: 'success',
  })
  @Get('freeze/:id')
  @RequireLogin()
  async freezeUser(@Param('id') id: number) {
    await this.userService.freezeUserById(id);
    return 'success';
  }
  // 查询用户列表
  @Get('list')
  @RequireLogin()
  async list(
    @Query('pageNo', new DefaultValuePipe(1), generateParseIntPipe('pageNo'))
    pageNo: number,
    @Query(
      'pageSize',
      new DefaultValuePipe(2),
      generateParseIntPipe('pageSize'),
    )
    pageSize: number,
    @Query('username')
    username: string,
    @Query('nickName')
    nickName: string,
    @Query('email')
    email: string,
  ) {
    return await this.userService.findList(
      pageNo,
      pageSize,
      username,
      nickName,
      email,
    );
  }
  @Post('upload')
  @UseInterceptors(
    FileInterceptor('file', {
      dest: 'upload',
      limits: {
        fileSize: 1024 * 1024 * 10,
      },
      storage: storage,
      fileFilter(req, file, callback) {
        // 获取文件扩展名
        const extname = path.extname(file.originalname);
        if (['.png', '.jpg', '.gif'].includes(extname)) {
          callback(null, true);
        } else {
          callback(new BadRequestException('只能上传图片'), false);
        }
      },
    }),
  )
  upload(@UploadedFile() file: Express.Multer.File) {
    return file.path;
  }
}
